package com.jmb.apiplatform.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jmb.apiplatform.common.LoginUserInfo;
import com.jmb.apiplatform.common.PageResult;
import com.jmb.apiplatform.cores.parser.Parser;
import com.jmb.apiplatform.exception.BusinessException;
import com.jmb.apiplatform.exception.ValidException;
import com.jmb.apiplatform.mapper.ApiTestCaseRelyDataMapper;
import com.jmb.apiplatform.pojo.*;
import com.jmb.apiplatform.service.ApiTestCaseRelyDataService;
import com.jmb.apiplatform.service.ApiTestCaseService;
import com.jmb.apiplatform.service.ApiTestPreCaseService;
import com.jmb.apiplatform.util.ValidUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class ApiTestCaseRelyDataServiceImpl implements ApiTestCaseRelyDataService {
    @Autowired
    private ApiTestCaseRelyDataMapper apiTestCaseRelyDataMapper;
    @Autowired
    private ApiTestCaseService apiTestCaseService;

    @Autowired
    private Parser parser;
    @Autowired
    private ApiTestPreCaseService apiTestPreCaseService;

    @Autowired
    private LoginUserInfo loginUserInfo;


    @Override
    public void saveApiTestCaseRelyData(ApiTestCaseRelyData relyData, HttpServletRequest request) throws ValidException {
        Integer contentType = relyData.getContentType();
        log.info("提取数据类型为{}",contentType);
        ValidUtil.notNUll(contentType, "提取数据类型不能为空");
        String extractExpression = relyData.getExtractExpression();
        if (contentType==0){
            ValidUtil.isJsonPath(extractExpression);
        }else if (contentType==1){
            ValidUtil.isXmlPath(extractExpression);
        }
        // 判断relyCaseId是否存在
        Integer relyCaseId = relyData.getRelyCaseId();
        if (apiTestCaseService.findApiTestByCaseId(relyCaseId) == null){
            throw new ValidException("依赖数据用例编号不存在");
        }
        // 判断relyName是否存在
        String relyName = relyData.getRelyName();
        if (apiTestCaseRelyDataMapper.selectRelyDataByName(relyName)!=null){
            throw new ValidException("依赖数据名称已存在其他依赖");
        }
        if(this.findIfRelyDataByName(relyName)!=null){
            throw new ValidException("依赖数据名称已存在接口依赖");
        }
        relyData.setCreatedTime(new Date());
        this.checkDependency(relyData);
        String realName = loginUserInfo.getRealName(request);
        Integer userId = loginUserInfo.getUserId(request);
        relyData.setCreatorName(realName);
        relyData.setCreatorId(userId);
        apiTestCaseRelyDataMapper.insertRelyData(relyData);
    }

    @Override
    public ApiTestCaseRelyDataVO findIfRelyDataByName(String relyName) {
        return apiTestCaseRelyDataMapper.selectRelyDataByName(relyName);
    }

    @Override
    public PageResult<ApiTestCaseRelyDataVO> findApiTestCaseRelyDataList(ApiTestCaseRelyDataTO apiTestCaseRelyDataListTO) throws ValidException {
        Integer pageNum = apiTestCaseRelyDataListTO.getPageNum();
        Integer pageSize = apiTestCaseRelyDataListTO.getPageSize();
        PageHelper.startPage(pageNum, pageSize);

        List<ApiTestCaseRelyDataVO> relyDataVOS = apiTestCaseRelyDataMapper.selectRelyDataList(apiTestCaseRelyDataListTO);
        // 想拼接出来数据，但是出现了类型转换错误，先放这里，后期优化
//        for (ApiTestCaseRelyDataVO dataVO : apiTestCaseRelyDataMapper.selectRelyDataList(apiTestCaseRelyDataListTO)) {
//            Integer relyCaseId = dataVO.getRelyCaseId();
//            Integer projectId = apiTestCaseService.findApiTestByCaseId(relyCaseId).getProjectId();
//            // 查询项目url
//            ProjectDao projectDao = new ProjectDao();
//            projectDao.setProjectId(projectId);
//            ProjectDao project = projectService.findProject(projectDao);
//            String domain = project.getDomain();
//            String protocol = project.getDevProtocol();
//            Integer prodPort = project.getProdPort();
//            // 拼接进入
//            dataVO.setCaseUrl(protocol + "://" + domain + "/" + prodPort);
//            list.add(dataVO);
//        }
//        PageInfo<ApiTestCaseRelyDataVO> pageInfo = new PageInfo<>(list);
        Page<ApiTestCaseRelyDataVO> page = (Page<ApiTestCaseRelyDataVO>) relyDataVOS;
        return new PageResult<>(page.getTotal(), page.getResult());
    }

    /**
     * 修改接口依赖
     * @param relyData 修改的参数
     * @throws ValidException
     */
    @Override
    public void modifyIfRelyData(ApiTestCaseRelyData relyData,HttpServletRequest request) throws ValidException {
        Integer userId = loginUserInfo.getUserId(request);
        Integer relyId = relyData.getRelyId();
        ApiTestCaseRelyDataVO ifRelyData = this.findIfRelyData(relyId);
        Integer modifiable = ifRelyData.getOthersModifiable();
        Integer creatorId = ifRelyData.getCreatorId();
        if (modifiable == null ||  creatorId == null) {
            throw new ValidException("仅允许创建人修改");
        }
        if (creatorId != userId) {
            if (modifiable.intValue() == 1) {
                throw new ValidException("仅允许创建人修改");
            }
            // 当前编辑人与创建人不一致时，不允许修改othersModifiable和othersDeletable字段
            ifRelyData.setOthersDeletable(null);
            ifRelyData.setOthersModifiable(null);
        }

        // 检查提取表达式
        Integer contentType = ifRelyData.getContentType(); // 提取数据类型   0json/1html/2header/
        String extractExpression = relyData.getExtractExpression();
        if (contentType == 0) {
            ValidUtil.isJsonPath(extractExpression);
        } else if (contentType == 1) {
            ValidUtil.isXmlPath(extractExpression);
        }
        // 判断relyCaseId是否存在
        Integer caseId = relyData.getRelyCaseId();
        if (apiTestCaseService.findApiTestByCaseId(caseId) == null) {
            log.warn("修改接口依赖，用例编号不存在，caseId={}", caseId);
            throw new ValidException("用例编号不存在");
        }
        // 判断relyName是否已存在
        String relyName = relyData.getRelyName();
        if (apiTestCaseRelyDataMapper.selectRelyDataByName(relyName) != null) {
            log.warn("修改接口依赖，依赖名称已存在于其它依赖，relyName={}", relyName);
            throw new ValidException("依赖名称已存在于其它依赖");
        }
        if (!apiTestCaseRelyDataMapper.checkRelyName(relyData).isEmpty()) {
            log.warn("修改接口依赖，依赖名称已存在于接口依赖，relyName={}", relyName);
            throw new ValidException("依赖名称已存在于接口依赖");
        }
        // 检查依赖名称合法性
        this.checkDependency(relyData);
        apiTestCaseRelyDataMapper.updateByRelyData(relyData);
    }

    @Override
    public ApiTestCaseRelyDataVO findIfRelyData(Integer relyId) {
          return apiTestCaseRelyDataMapper.selectByRelyId(relyId);
    }

    @Override
    public void removeIfRelyData(Integer relyId, HttpServletRequest request) throws ValidException {
        // 获取当前删除人userId
        int userId = loginUserInfo.getUserId(request);
        ApiTestCaseRelyDataVO ifRelyData = this.findIfRelyData(relyId);
        Integer deletable = ifRelyData.getOthersDeletable();
        Integer creatorId = ifRelyData.getCreatorId();
        if (deletable == null ||  creatorId == null) {
            throw new ValidException("仅允许创建人删除");
        }
        if (creatorId != userId && deletable.intValue() == 1) {
            throw new ValidException("仅允许创建人删除");
        }
        apiTestCaseRelyDataMapper.deleteByRelyId(relyId);

    }

//    @Override
//    public String checkRelyResult(Integer relyId, String executor) throws ValidException {
//        log.info("------------------------------执行接口预检操作------------------------------");
//        ApiTestCaseRelyDataVO relyData = apiTestCaseRelyDataService.findIfRelyData(relyId);
//        if (null == relyData) {
//            log.warn("预检接口依赖，未找到该接口依赖，relyId={}", relyId);
//            throw new ValidException("未找到该接口依赖");
//        }
//        Integer caseId = relyData.getRelyCaseId();
//        log.info("------------------------------进入无下标取值模式------------------------------");
//        // 根据caseId调用相应case
//        log.info("根据caseId调用相应case，caseId={}", caseId);
//
////        String chainNo = NoUtil.genChainNo();
////        Integer executeLogId = interfaceCaseService.executeInterfaceCase(new ExecuteInterfaceCaseParam(caseId, executor,
////                null, chainNo, null, (byte) 1, null, null,
////                null, null, (byte)1, null, false));
//        // redisUtil.stackPush(chainNo, executeLogId); delete
//
////        log.info("调用成功，executeLogId={}", executeLogId);
//        // 获取case执行结果, 不等于0, 则用例未通过
////        if (executeLogService.findExecute(executeLogId).getStatus() != 0) {
////            LOG.warn("预检接口依赖，前置用例执行未通过，executeLogId={}", executeLogId);
////            throw new BusinessException("前置用例执行未通过");
////        }
//        // 根据executeLogId查询对应的执行记录
//        InterfaceCaseExecuteLogVO interfaceCaseExecuteLogVO = executeLogService.findExecute(executeLogId);
//        String responseBody = interfaceCaseExecuteLogVO.getResponseBody();
//        String responseHeaders = interfaceCaseExecuteLogVO.getResponseHeaders();
//        LOG.info("responseBody={}，responseHeaders={}", responseBody, responseHeaders);
//        // 根据contentType来确定对何字段进行替换, 提取数据类型   0json/1html/2header/
//        int contentType = (int) interfaceCaseRelyData.getContentType();
//        String expression = interfaceCaseRelyData.getExtractExpression();
//        try {
//            if (contentType == 0) { // json
//                LOG.info("------------------------------根据jsonPath取值");
//                ArrayList jsonPathArray = JSONObject.parseObject(ParseUtil.parseJson(responseBody, expression), ArrayList.class);
//                if (jsonPathArray.isEmpty()) {
//                    LOG.warn("预检接口依赖，提取方式为jsonPath，提取内容为空，expression={}", expression);
//                    throw new ParseException(expression + "提取内容为空");
//                }
//                if (jsonPathArray.size() == 1) {
//                    Object o = jsonPathArray.get(0);
//                    String s = o == null ? null : o.toString();
//                    LOG.info("提取内容为：{}",s);
//                    return s;
//                } else {
//                    LOG.info("提取内容为：{}", JSON.toJSONString(jsonPathArray));
//                    return JSON.toJSONString(jsonPathArray);
//                }
//            } else if (contentType == 1) { // html
//                LOG.info("------------------------------根据xpath取值");
//                ArrayList xpathArray = JSONObject.parseObject(ParseUtil.parseXml(responseBody, expression), ArrayList.class);
//                if (xpathArray.isEmpty()) {
//                    LOG.warn("预检接口依赖，提取方式为xpath，提取内容为空，expression={}", expression);
//                    throw new ParseException(expression + "提取内容为空");
//                }
//                if (xpathArray.size() == 1) {
//                    Object o = xpathArray.get(0);
//                    String s = o == null ? null : o.toString();
//                    LOG.info("提取内容为：{}",s);
//                    return s;
//                } else {
//                    LOG.info("提取内容为：{}", JSON.toJSONString(xpathArray));
//                    return JSON.toJSONString(xpathArray);
//                }
//            } else if (contentType == 2) { // headers
//                LOG.info("------------------------------根据header取值");
//                JSONArray headerArray = (JSONArray) JSONObject.parseObject(responseHeaders,
//                        HashMap.class).get(expression);
//                if (headerArray == null || headerArray.isEmpty()) {
//                    LOG.warn("预检接口依赖，提取方式为headers，未找到请求头，expression={}",expression);
//                    throw new ParseException("未找到请求头:" + expression);
//                } else {
//                    if (headerArray.size() == 1) {
//                        Object o = headerArray.get(0);
//                        String s = o == null ? null : o.toString();
//                        LOG.info("提取内容为：{}",s);
//                        return s;
//                    } else {
//                        LOG.info("提取内容为：{}", JSON.toJSONString(headerArray));
//                        return JSON.toJSONString(headerArray);
//                    }
//                }
//            } else {
//                LOG.warn("不支持该种取值方式, contentType={}", contentType);
//                throw new BusinessException("不支持该种取值方式");
//            }
//        } catch (BusinessException e) {
//            LOG.warn("不支持该种取值方式, contentType={}", contentType);
//            throw new BusinessException("不支持该种取值方式");
//        } catch (Exception e) {
//            LOG.error("预检接口依赖出现异常，errorMsg={}", ExceptionUtil.msg(e));
//            throw new ParseException(e.getMessage());
//        }
//    }


    /**
     * 检查依赖名称合理性
     * @param ifRelyDataDO ifRelyDataDO
     * @throws BusinessException BusinessException
     */
    private void checkDependency(ApiTestCaseRelyData ifRelyDataDO) throws ValidException {
        Integer relyCaseId = ifRelyDataDO.getRelyCaseId();
        String name = ifRelyDataDO.getRelyName();

        // 如果是接口依赖，确保接口依赖本身的headers、params、form-data、form-data-encoded、raw、断言预期结果不包含当前依赖名称
        ApiTestCaseInfoVO caseInfo = apiTestCaseService.findApiTestByCaseId(relyCaseId);
        String headers = caseInfo.getHeaders();
        String params = caseInfo.getParams();
        String formData = caseInfo.getFormData();
        String formDataEncoded = caseInfo.getFormDataEncoded();
        String raw = caseInfo.getRaw();
        List<ApiTestAssertVO> asserts = caseInfo.getAsserts();

        // 从headers中检查
        this.checkProperty(name, headers, "headers", false);

        // 从params中检查
        this.checkProperty(name, params, "params", false);

        // 从formData中检查
        this.checkProperty(name, formData, "formData", false);

        // 从formDataEncoded中检查
        this.checkProperty(name, formDataEncoded, "formDataEncoded", false);

        // 从raw中检查
        this.checkProperty(name, raw, "raw", false);

        // 从断言预期结果检查
        for (ApiTestAssertVO interfaceAssertVO : asserts) {
            String exceptedResult = interfaceAssertVO.getExceptedResult();
            this.checkProperty(name, exceptedResult, "断言预期结果", false);
        }

        // 如果是接口依赖，确保接口依赖前置用例的headers、params、form-data、form-data-encoded、raw、断言预期结果不包含当前依赖名称
        List<Integer> preCaseIdList = apiTestPreCaseService.findApiTestPreCaseById(relyCaseId);
        for (Integer preCaseId : preCaseIdList) {
            ApiTestCaseInfoVO preCaseInfo = apiTestCaseService.findApiTestByCaseId(preCaseId);
            String preHeaders = preCaseInfo.getHeaders();
            String preParams = preCaseInfo.getParams();
            String preFormData = preCaseInfo.getFormData();
            String preFormDataEncoded = preCaseInfo.getFormDataEncoded();
            String preRaw = preCaseInfo.getRaw();
            List<ApiTestAssertVO> preCaseInfoAsserts = preCaseInfo.getAsserts();

            // 从headers中检查
            this.checkProperty(name, preHeaders, String.format("[%s]headers", preCaseId), true);

            // 从params中检查
            this.checkProperty(name, preParams, String.format("[%s]params", preCaseId), true);

            // 从formData中检查
            this.checkProperty(name, preFormData, String.format("[%s]formData", preCaseId), true);

            // 从formDataEncoded中检查
            this.checkProperty(name, preFormDataEncoded, String.format("[%s]formDataEncoded", preCaseId), true);

            // 从raw中检查
            this.checkProperty(name, preRaw, String.format("[%s]raw", preCaseId), true);

            // 从断言预期结果检查
            for (ApiTestAssertVO interfaceAssertVO : preCaseInfoAsserts) {
                String exceptedResult = interfaceAssertVO.getExceptedResult();
                this.checkProperty(name, exceptedResult, String.format("[%s]断言预期结果", preCaseId), true);
            }
        }
    }
    /**
     * 从不同域中检查依赖名称是否合法
     * @param dependencyName 依赖名称
     * @param property 域，如headers、params、formdata、formdataencoded、raw
     * @param propertyDesc 描述
     * @param isPreCase 是否是前置用例
     * @throws BusinessException 异常
     */
    private void checkProperty(String dependencyName, String property, String propertyDesc, boolean isPreCase) throws ValidException {
        for (String s : parser.extractDependencyName(property)) {
            if (s.equals(dependencyName)) {
                if (!isPreCase) {
                    throw new ValidException(String.format("被绑定用例%s不能引用当前依赖名称", propertyDesc));
                } else {
                    throw new ValidException(String.format("被绑定用例的前置用例%s不能引用当前依赖名称", propertyDesc));
                }
            }
//            RelyDataVO vo = relyDataMapper.selectRelyDataByName(s);
//            if (vo != null) {
//                int type = vo.getType().intValue();
//                if (type > 1) {
//                    String value = vo.getValue();
//                    if (parser.extractDependencyName(value).contains(dependencyName)) {
//                        if (!isPreCase) {
//                            throw new BusinessException(String.format("被绑定用例%s的SQL依赖中不能引用当前依赖名称", propertyDesc));
//                        } else {
//                            throw new BusinessException(String.format("被绑定用例的前置用例%s的SQL依赖中不能引用当前依赖名称", propertyDesc));
//                        }
//                    }
//                }
//            }
        }
    }
}
